@yltrcc/vditor 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +236 -692
- package/dist/index.css +130 -34
- package/dist/index.js +98 -3
- package/dist/index.min.js +1 -1
- package/dist/method.js +3 -3
- package/dist/method.min.js +1 -1
- package/package.json +2 -3
- package/src/assets/less/_ir.less +49 -0
- package/src/assets/less/_wysiwyg.less +134 -72
- package/src/ts/util/processCode.ts +166 -0
package/README.md
CHANGED
|
@@ -1,773 +1,317 @@
|
|
|
1
|
-
|
|
2
|
-
<img alt="Vditor" src="https://b3log.org/images/brand/vditor-128.png" />
|
|
1
|
+
# yl-vditor 技术架构文档
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
易于使用的 Markdown 编辑器,为适配不同的应用场景而生
|
|
6
|
-
<br><br>
|
|
7
|
-
<a title="MIT" target="_blank" href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-orange.svg?style=flat-square"></a>
|
|
8
|
-
<a title="npm bundle size" target="_blank" href="https://www.npmjs.com/package/vditor"><img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/vditor?style=flat-square&color=blueviolet"></a>
|
|
9
|
-
<a title="Version" target="_blank" href="https://www.npmjs.com/package/vditor"><img src="https://img.shields.io/npm/v/vditor.svg?style=flat-square"></a><br>
|
|
10
|
-
<a title="Downloads" target="_blank" href="https://www.npmjs.com/package/vditor"><img src="https://img.shields.io/npm/dt/vditor.svg?style=flat-square&color=97ca00"></a>
|
|
11
|
-
<a title="jsdelivr" target="_blank" href="https://www.jsdelivr.com/package/npm/vditor"><img src="https://data.jsdelivr.com/v1/package/npm/vditor/badge"/></a>
|
|
12
|
-
<a title="Hits" target="_blank" href="https://github.com/88250/hits"><img src="https://hits.b3log.org/Vanessa219/vditor.svg"></a> <br><br>
|
|
13
|
-
<a title="GitHub Watchers" target="_blank" href="https://github.com/Vanessa219/vditor/watchers"><img src="https://img.shields.io/github/watchers/Vanessa219/vditor.svg?label=Watchers&style=social"></a>
|
|
14
|
-
<a title="GitHub Stars" target="_blank" href="https://github.com/Vanessa219/vditor/stargazers"><img src="https://img.shields.io/github/stars/Vanessa219/vditor.svg?label=Stars&style=social"></a>
|
|
15
|
-
<a title="GitHub Forks" target="_blank" href="https://github.com/Vanessa219/vditor/network/members"><img src="https://img.shields.io/github/forks/Vanessa219/vditor.svg?label=Forks&style=social"></a>
|
|
16
|
-
<a title="Author GitHub Followers" target="_blank" href="https://github.com/vanessa219"><img src="https://img.shields.io/github/followers/vanessa219.svg?label=Followers&style=social"></a>
|
|
17
|
-
</p>
|
|
3
|
+
TypeScript 实现的浏览器端 Markdown 编辑器。
|
|
18
4
|
|
|
19
|
-
|
|
20
|
-
<a href="https://github.com/Vanessa219/vditor/blob/master/README_en_US.md">English</a> | <a href="https://b3log.org/vditor/demo/index.html">Demo</a>
|
|
21
|
-
</p>
|
|
5
|
+
---
|
|
22
6
|
|
|
23
|
-
|
|
24
|
-
🔥 欢迎观摩我们的另一个开源项目 <a href="https://github.com/siyuan-note/siyuan">思源笔记</a>
|
|
25
|
-
<p>
|
|
7
|
+
## 目录
|
|
26
8
|
|
|
27
|
-
|
|
9
|
+
- [项目概述](#项目概述)
|
|
10
|
+
- [核心目录结构](#核心目录结构)
|
|
11
|
+
- [三种编辑模式](#三种编辑模式)
|
|
12
|
+
- [主入口文件](#主入口文件)
|
|
13
|
+
- [核心模块详解](#核心模块详解)
|
|
14
|
+
- [渲染流程](#渲染流程)
|
|
15
|
+
- [扩展功能模块](#扩展功能模块)
|
|
16
|
+
- [开发环境](#开发环境)
|
|
28
17
|
|
|
29
|
-
|
|
18
|
+
---
|
|
30
19
|
|
|
31
|
-
|
|
20
|
+
## 项目概述
|
|
32
21
|
|
|
33
|
-
|
|
22
|
+
yl-vditor 是一个基于 TypeScript 开发的浏览器端 Markdown 编辑器,支持三种编辑模式:WYSIWYG(所见即所得)、IR(即时渲染)、SV(分屏预览)。
|
|
34
23
|
|
|
35
|
-
|
|
24
|
+
核心特点:
|
|
25
|
+
- 使用 TypeScript 实现
|
|
26
|
+
- 基于 Lute 引擎进行 Markdown 解析
|
|
27
|
+
- 支持模块化扩展
|
|
28
|
+
- 支持多种框架集成
|
|
36
29
|
|
|
37
|
-
|
|
30
|
+
---
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
* 有的同时支持所见即所得和分屏预览,但所见即所得模式下不能完整支持 Markdown 语法排版
|
|
41
|
-
* 几乎没有类似 Typora 的即时渲染
|
|
32
|
+
## 核心目录结构
|
|
42
33
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
* 录音支持,用户可直接发布语音
|
|
68
|
-
* 粘贴 HTML 自动转换为 Markdown,如粘贴中包含外链图片可通过指定接口上传到服务器
|
|
69
|
-
* 支持主窗口大小拖拽、字符计数
|
|
70
|
-
* 多主题支持,内置黑白绿三套主题
|
|
71
|
-
* 多语言支持,内置中、英、韩文本地化
|
|
72
|
-
* 支持主流浏览器,对移动端友好
|
|
73
|
-
|
|
74
|
-

|
|
75
|
-
|
|
76
|
-

|
|
77
|
-
|
|
78
|
-
## 🔮 编辑模式
|
|
79
|
-
|
|
80
|
-
### 所见即所得(WYSIWYG)
|
|
81
|
-
|
|
82
|
-
*所见即所得*模式对不熟悉 Markdown 的用户较为友好,熟悉 Markdown 的话也可以无缝使用。
|
|
34
|
+
```
|
|
35
|
+
yl-vditor/
|
|
36
|
+
├── src/
|
|
37
|
+
│ ├── index.ts # 主入口,Vditor 类
|
|
38
|
+
│ ├── method.ts # 静态工具方法
|
|
39
|
+
│ ├── assets/ # 静态资源
|
|
40
|
+
│ │ ├── less/ # 样式文件
|
|
41
|
+
│ │ ├── images/ # 图片资源
|
|
42
|
+
│ │ └── js/ # 第三方库 (highlight, katex, mermaid, lute 等)
|
|
43
|
+
│ └── ts/ # TypeScript 源码
|
|
44
|
+
│ ├── constants.ts # 常量定义
|
|
45
|
+
│ ├── ir/ # IR 模式 (即时渲染模式)
|
|
46
|
+
│ ├── sv/ # SV 模式 (分屏预览模式)
|
|
47
|
+
│ ├── wysiwyg/ # WYSIWYG 模式 (所见即所得)
|
|
48
|
+
│ ├── toolbar/ # 工具栏
|
|
49
|
+
│ ├── markdown/ # Markdown 渲染相关
|
|
50
|
+
│ ├── preview/ # 预览相关
|
|
51
|
+
│ ├── hint/ # 提示补全
|
|
52
|
+
│ ├── upload/ # 文件上传
|
|
53
|
+
│ ├── undo/ # 撤销重做
|
|
54
|
+
│ ├── util/ # 工具函数
|
|
55
|
+
│ └── ui/ # UI 相关
|
|
56
|
+
└── package.json
|
|
57
|
+
```
|
|
83
58
|
|
|
84
|
-
|
|
59
|
+
---
|
|
85
60
|
|
|
86
|
-
|
|
61
|
+
## 三种编辑模式
|
|
87
62
|
|
|
88
|
-
|
|
63
|
+
| 模式 | 名称 | 目录 | 说明 |
|
|
64
|
+
|------|------|------|------|
|
|
65
|
+
| WYSIWYG | 所见即所得 | `src/ts/wysiwyg/` | 对不熟悉 Markdown 的用户友好 |
|
|
66
|
+
| IR | 即时渲染 | `src/ts/ir/` | 类似 Typora,理论最优雅 |
|
|
67
|
+
| SV | 分屏预览 | `src/ts/sv/` | 传统模式,左右分屏 |
|
|
89
68
|
|
|
90
|
-
|
|
69
|
+
---
|
|
91
70
|
|
|
92
|
-
|
|
71
|
+
## 主入口文件
|
|
93
72
|
|
|
94
|
-
|
|
73
|
+
### src/index.ts
|
|
95
74
|
|
|
96
|
-
|
|
75
|
+
`Vditor` 类是整个编辑器的主入口,在 `init()` 方法中初始化所有组件:
|
|
97
76
|
|
|
98
|
-
|
|
77
|
+
```typescript
|
|
78
|
+
class Vditor {
|
|
79
|
+
constructor(id: string | HTMLElement, options?: IOptions)
|
|
80
|
+
|
|
81
|
+
init() {
|
|
82
|
+
// 初始化各模块
|
|
83
|
+
this.vditor.lute = new Lute(...)
|
|
84
|
+
this.vditor.sv = new SV(this.vditor)
|
|
85
|
+
this.vditor.wysiwyg = new WYSIWYG(this.vditor)
|
|
86
|
+
this.vditor.ir = new IR(this.vditor)
|
|
87
|
+
this.vditor.toolbar = new Toolbar(this.vditor)
|
|
88
|
+
this.vditor.preview = new Preview(this.vditor)
|
|
89
|
+
this.vditor.hint = new Hint(this.vditor)
|
|
90
|
+
this.vditor.undo = new Undo(this.vditor)
|
|
91
|
+
this.vditor.upload = new Upload(this.vditor)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
99
95
|
|
|
100
|
-
|
|
101
|
-
* 所有 GFM 语法:表格、任务列表项、删除线、自动链接、XSS 过滤
|
|
102
|
-
* 常用 Markdown 扩展语法:脚注、ToC、自定义标题 ID
|
|
103
|
-
* 图表语法
|
|
104
|
-
* 流程图、时序图、甘特图,通过 Mermaid 支持
|
|
105
|
-
* Graphviz
|
|
106
|
-
* 折线图、饼图、脑图等,通过 ECharts 支持
|
|
107
|
-
* 五线谱:通过 abc.js 支持
|
|
108
|
-
* 数学公式:数学公式块、行级数学公式,通过 MathJax 和 KaTeX 支持
|
|
109
|
-
* YAML Front Matter
|
|
110
|
-
* 中文语境优化
|
|
111
|
-
* 中西文之间插入空格
|
|
112
|
-
* 术语拼写修正
|
|
113
|
-
* 中文后跟英文逗号句号等标点替换为中文对应标点
|
|
96
|
+
### src/method.ts
|
|
114
97
|
|
|
115
|
-
|
|
98
|
+
静态工具方法集合,包含:
|
|
99
|
+
- `md2html()`: Markdown 转 HTML
|
|
100
|
+
- `preview()`: 页面 Markdown 渲染
|
|
101
|
+
- `mermaidRender()`: 流程图渲染
|
|
102
|
+
- `mathRender()`: 数学公式渲染
|
|
103
|
+
- `codeRender()`: 代码块渲染
|
|
104
|
+
- 等等...
|
|
116
105
|
|
|
117
|
-
|
|
106
|
+
---
|
|
118
107
|
|
|
119
|
-
|
|
120
|
-
* [Solo](https://github.com/88250/solo) & [Pipe](https://github.com/88250/pipe) B3log 分布式社区的博客端节点,欢迎加入下一代社区网络
|
|
121
|
-
* [Tditor](https://tditor.com) 基于React、Vditor、Springboot,一款打造极致文字创作体验的在线Markdown编辑平台
|
|
122
|
-
* [Arya](https://github.com/nicejade/markdown-online-editor) 基于 Vue、Vditor,所构建的在线 Markdown 编辑器
|
|
123
|
-
* [更多案例](https://github.com/Vanessa219/vditor/network/dependents?package_id=UGFja2FnZS0zMTY2Mzg4MzE%3D)
|
|
108
|
+
## 核心模块详解
|
|
124
109
|
|
|
125
|
-
|
|
110
|
+
### 1. WYSIWYG 模式 (`src/ts/wysiwyg/`)
|
|
126
111
|
|
|
127
|
-
|
|
112
|
+
| 文件 | 功能 |
|
|
113
|
+
|------|------|
|
|
114
|
+
| `index.ts` | 主类,绑定事件(复制/剪切/粘贴/拖拽等) |
|
|
115
|
+
| `input.ts` | 输入处理,调用 SpinVditorDOM 渲染 |
|
|
116
|
+
| `renderDomByMd.ts` | Markdown 渲染 + 图片尺寸处理 + 文档链接处理 |
|
|
117
|
+
| `afterRenderEvent.ts` | 渲染后事件处理 |
|
|
118
|
+
| `keydown.ts` | 键盘事件处理 |
|
|
119
|
+
| `paste.ts` | 粘贴事件处理 |
|
|
120
|
+
| `cut.ts` | 剪切事件处理 |
|
|
121
|
+
| `drop.ts` | 拖放事件处理 |
|
|
128
122
|
|
|
129
|
-
|
|
123
|
+
### 2. IR 模式 (`src/ts/ir/`)
|
|
130
124
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
125
|
+
| 文件 | 功能 |
|
|
126
|
+
|------|------|
|
|
127
|
+
| `index.ts` | 主类,初始化 IR 编辑器 |
|
|
128
|
+
| `input.ts` | 输入处理 |
|
|
129
|
+
| `keydown.ts` | 键盘事件处理 |
|
|
130
|
+
| `paste.ts` | 粘贴事件处理 |
|
|
134
131
|
|
|
135
|
-
|
|
132
|
+
### 3. SV 模式 (`src/ts/sv/`)
|
|
136
133
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
134
|
+
| 文件 | 功能 |
|
|
135
|
+
|------|------|
|
|
136
|
+
| `index.ts` | 主类,初始化 SV 编辑器 |
|
|
137
|
+
| `input.ts` | 输入处理 |
|
|
138
|
+
| `keydown.ts` | 键盘事件处理 |
|
|
140
139
|
|
|
141
|
-
|
|
142
|
-
```
|
|
140
|
+
### 4. 工具栏模块 (`src/ts/toolbar/`)
|
|
143
141
|
|
|
144
|
-
|
|
142
|
+
| 文件 | 功能 |
|
|
143
|
+
|------|------|
|
|
144
|
+
| `index.ts` | 主类,生成工具栏 |
|
|
145
|
+
| `MenuItem.ts` | 菜单项基类 |
|
|
146
|
+
| `items/` | 各菜单项实现 |
|
|
145
147
|
|
|
146
|
-
|
|
148
|
+
内置 36+ 个菜单项,包括:
|
|
149
|
+
- `Bold`: 粗体
|
|
150
|
+
- `Italic`: 斜体
|
|
151
|
+
- `Headings`: 标题
|
|
152
|
+
- `Emoji`: 表情
|
|
153
|
+
- `Upload`: 上传
|
|
154
|
+
- `Record`: 录音
|
|
155
|
+
- 等等...
|
|
147
156
|
|
|
148
|
-
|
|
149
|
-
<!-- ⚠️生产环境请指定版本号,如 https://unpkg.com/vditor@x.x.x/dist... -->
|
|
150
|
-
<link rel="stylesheet" href="https://unpkg.com/vditor/dist/index.css" />
|
|
151
|
-
<script src="https://unpkg.com/vditor/dist/index.min.js"></script>
|
|
152
|
-
```
|
|
157
|
+
### 5. Markdown 模块 (`src/ts/markdown/`)
|
|
153
158
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
* [在Svelte中使用](https://github.com/HerbertHe/svelte-vditor-demo)
|
|
160
|
-
|
|
161
|
-
### 主题
|
|
162
|
-
|
|
163
|
-
#### 编辑器主题
|
|
164
|
-
|
|
165
|
-
编辑器所展现的外观。内置classic,dark 2 套主题。
|
|
166
|
-
|
|
167
|
-
* 编辑器初始化时可通过 `options.theme` 设置内置主题
|
|
168
|
-
* 初始化完成后可通过 `setTheme` 更新编辑器主题
|
|
169
|
-
* 可通过修改 [index.less](https://github.com/Vanessa219/vditor/blob/master/src/assets/less/index.less) 中的变量对主题颜色进行定制
|
|
170
|
-
* 可参考现有结构和类名在原有基础上进行修改
|
|
171
|
-
|
|
172
|
-
#### 内容主题
|
|
173
|
-
|
|
174
|
-
Markdown 输出的 HTML 所展现的外观。内置 ant-design, light,dark,wechat 4 套主题。支持内容主题扩展接口。
|
|
175
|
-
|
|
176
|
-
* 需在显示元素上添加 `class="vditor-reset"`
|
|
177
|
-
* 编辑器初始化时可通过 `options.preview.theme` 设置内置或自己开发的主题列表
|
|
178
|
-
* 内容渲染初始化时可通过 `IPreviewOptions.theme` 设置内置或自己开发的主题
|
|
179
|
-
* 初始化完成后可通过 `setTheme` 或 `setContentTheme` 更新内容主题
|
|
180
|
-
|
|
181
|
-
#### 代码主题
|
|
182
|
-
|
|
183
|
-
代码块所展现的外观。内置 github 等 36 套主题。
|
|
184
|
-
|
|
185
|
-
* 编辑器初始化时可通过 `options.preview.hljs` 对代码块样式、行号、是否启用进行设置
|
|
186
|
-
* 内容渲染初始化时可通过 `IPreviewOptions.hljs` 对代码块样式、行号、是否启用进行设置
|
|
187
|
-
* 初始化完成后可通过 `setTheme` 或 `setCodeTheme` 更新代码主题
|
|
188
|
-
|
|
189
|
-
### API
|
|
190
|
-
|
|
191
|
-
#### id
|
|
192
|
-
|
|
193
|
-
可填入元素 `id` 或元素自身 `HTMLElement`
|
|
194
|
-
|
|
195
|
-
⚠️:当填入元素自身的 `HTMLElement` 时需设置 `options.cache.id` 或将 `options.cache.enable` 设置为 `false`
|
|
196
|
-
|
|
197
|
-
#### options
|
|
198
|
-
|
|
199
|
-
| | 说明 | 默认值 |
|
|
200
|
-
| - | - | - |
|
|
201
|
-
| i18n | 多语言,参见 ITips | - |
|
|
202
|
-
| undoDelay | 历史记录间隔 | - |
|
|
203
|
-
| after | 编辑器异步渲染完成后的回调方法 | - |
|
|
204
|
-
| height | 编辑器总高度 | 'auto' |
|
|
205
|
-
| minHeight | 编辑区域最小高度 | - |
|
|
206
|
-
| width | 编辑器总宽度,支持 % | 'auto' |
|
|
207
|
-
| placeholder | 输入区域为空时的提示 | '' |
|
|
208
|
-
| lang | 语言种类:de_DE, en_US, es_ES, fr_FR, ja_JP, ko_KR, pt_BR, ru_RU, sv_SE, vi_VN, zh_CN, zh_TW | 'zh_CN' |
|
|
209
|
-
| input(value: string) | 输入后触发 | - |
|
|
210
|
-
| focus(value: string) | 聚焦后触发 | - |
|
|
211
|
-
| blur(value: string) | 失焦后触发 | - |
|
|
212
|
-
| keydown(event: KeyboardEvent) | 按下后触发 | - |
|
|
213
|
-
| esc(value: string) | <kbd>esc</kbd> 按下后触发 | - |
|
|
214
|
-
| ctrlEnter(value: string) | <kbd>⌘/ctrl+enter</kbd> 按下后触发 | - |
|
|
215
|
-
| select(value: string) | 编辑器中选中文字后触发 | - |
|
|
216
|
-
| unSelect() | 编辑器中未选中文字后触发 | - |
|
|
217
|
-
| tab | <kbd>tab</kbd> 键操作字符串,支持 `\t` 及任意字符串 | - |
|
|
218
|
-
| typewriterMode | 是否启用打字机模式 | false |
|
|
219
|
-
| cdn | 配置自建 CDN 地址 | `https://unpkg.com/vditor@${VDITOR_VERSION}` |
|
|
220
|
-
| mode | 可选模式:sv, ir, wysiwyg | 'ir' |
|
|
221
|
-
| debugger | 是否显示日志 | false |
|
|
222
|
-
| value | 编辑器初始化值 | '' |
|
|
223
|
-
| theme | 主题:classic, dark | 'classic' |
|
|
224
|
-
| icon | 图标风格:ant, material | 'ant' |
|
|
225
|
-
| customRenders: {language: string, render: (element: HTMLElement, vditor: IVditor) => void}[] | 自定义渲染器 | [] |
|
|
226
|
-
| customWysiwygToolbar(type: TWYSISYGToolbar, element: HTMLElement): void | 对 wysiwyg 模式下的工具栏进行自定义 | - |
|
|
227
|
-
|
|
228
|
-
#### options.toolbar
|
|
229
|
-
|
|
230
|
-
* 工具栏,可使用 name 进行简写: `toolbar: ['emoji', 'br', 'bold', '|', 'line']` 。默认值参见 [src/ts/util/Options.ts](https://github.com/Vanessa219/vditor/blob/master/src/ts/util/Options.ts)
|
|
231
|
-
* name 可枚举为: `emoji`,`headings`,`bold`,`italic`,`strike`,`|`,`line`,`quote`,`list`,`ordered-list`,`check` ,`outdent` ,`indent`,`code`,`inline-code`,`insert-after`,`insert-before` ,`undo`,`redo`,`upload`,`link`,`table`,`record`,`edit-mode`,`both`,`preview`,`fullscreen`,`outline`,`code-theme`,`content-theme`,`export`, `devtools`,`info`,`help`,`br`
|
|
232
|
-
* 当 `name` 不在枚举中时,可以添加自定义按钮,格式如下:
|
|
233
|
-
|
|
234
|
-
```js
|
|
235
|
-
new Vditor('vditor', {
|
|
236
|
-
toolbar: [
|
|
237
|
-
{
|
|
238
|
-
hotkey: '⇧⌘S',
|
|
239
|
-
name: 'sponsor',
|
|
240
|
-
tipPosition: 's',
|
|
241
|
-
tip: '成为赞助者',
|
|
242
|
-
className: 'right',
|
|
243
|
-
icon: '<svg t="1589994565028" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2808" width="32" height="32"><path d="M506.6 423.6m-29.8 0a29.8 29.8 0 1 0 59.6 0 29.8 29.8 0 1 0-59.6 0Z" fill="#0F0F0F" p-id="2809"></path><path d="M717.8 114.5c-83.5 0-158.4 65.4-211.2 122-52.7-56.6-127.7-122-211.2-122-159.5 0-273.9 129.3-273.9 288.9C21.5 562.9 429.3 913 506.6 913s485.1-350.1 485.1-509.7c0.1-159.5-114.4-288.8-273.9-288.8z" fill="#FAFCFB" p-id="2810"></path><path d="M506.6 926c-22 0-61-20.1-116-59.6-51.5-37-109.9-86.4-164.6-139-65.4-63-217.5-220.6-217.5-324 0-81.4 28.6-157.1 80.6-213.1 53.2-57.2 126.4-88.8 206.3-88.8 40 0 81.8 14.1 124.2 41.9 28.1 18.4 56.6 42.8 86.9 74.2 30.3-31.5 58.9-55.8 86.9-74.2 42.5-27.8 84.3-41.9 124.2-41.9 79.9 0 153.2 31.5 206.3 88.8 52 56 80.6 131.7 80.6 213.1 0 103.4-152.1 261-217.5 324-54.6 52.6-113.1 102-164.6 139-54.8 39.5-93.8 59.6-115.8 59.6zM295.4 127.5c-72.6 0-139.1 28.6-187.3 80.4-47.5 51.2-73.7 120.6-73.7 195.4 0 64.8 78.3 178.9 209.6 305.3 53.8 51.8 111.2 100.3 161.7 136.6 56.1 40.4 88.9 54.8 100.9 54.8s44.7-14.4 100.9-54.8c50.5-36.3 108-84.9 161.7-136.6 131.2-126.4 209.6-240.5 209.6-305.3 0-74.9-26.2-144.2-73.7-195.4-48.2-51.9-114.7-80.4-187.3-80.4-61.8 0-127.8 38.5-201.7 117.9-2.5 2.6-5.9 4.1-9.5 4.1s-7.1-1.5-9.5-4.1C423.2 166 357.2 127.5 295.4 127.5z" fill="#141414" p-id="2811"></path><path d="M353.9 415.6m-33.8 0a33.8 33.8 0 1 0 67.6 0 33.8 33.8 0 1 0-67.6 0Z" fill="#0F0F0F" p-id="2812"></path><path d="M659.3 415.6m-33.8 0a33.8 33.8 0 1 0 67.6 0 33.8 33.8 0 1 0-67.6 0Z" fill="#0F0F0F" p-id="2813"></path><path d="M411.6 538.5c0 52.3 42.8 95 95 95 52.3 0 95-42.8 95-95v-31.7h-190v31.7z" fill="#5B5143" p-id="2814"></path><path d="M506.6 646.5c-59.6 0-108-48.5-108-108v-31.7c0-7.2 5.8-13 13-13h190.1c7.2 0 13 5.8 13 13v31.7c0 59.5-48.5 108-108.1 108z m-82-126.7v18.7c0 45.2 36.8 82 82 82s82-36.8 82-82v-18.7h-164z" fill="#141414" p-id="2815"></path><path d="M450.4 578.9a54.7 27.5 0 1 0 109.4 0 54.7 27.5 0 1 0-109.4 0Z" fill="#EA64F9" p-id="2816"></path><path d="M256 502.7a32.1 27.5 0 1 0 64.2 0 32.1 27.5 0 1 0-64.2 0Z" fill="#EFAFF9" p-id="2817"></path><path d="M703.3 502.7a32.1 27.5 0 1 0 64.2 0 32.1 27.5 0 1 0-64.2 0Z" fill="#EFAFF9" p-id="2818"></path></svg>',
|
|
244
|
-
click () {alert('捐赠地址:https://ld246.com/sponsor')},
|
|
245
|
-
}],
|
|
246
|
-
})
|
|
247
|
-
```
|
|
159
|
+
| 文件 | 功能 |
|
|
160
|
+
|------|------|
|
|
161
|
+
| `setLute.ts` | Lute 引擎配置 |
|
|
162
|
+
| `getMarkdown.ts` | 获取 Markdown 内容 |
|
|
163
|
+
| `export.ts` | 导出功能 |
|
|
248
164
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
| suffix | 插入编辑器中的后缀 | - |
|
|
257
|
-
| prefix | 插入编辑器中的前缀 | - |
|
|
258
|
-
| click(event: Event, vditor: IVditor) | 自定义按钮点击时触发的事件 | - |
|
|
259
|
-
| className | 样式名 | '' |
|
|
260
|
-
| toolbar?: Array<options.toolbar> | 子菜单 | - |
|
|
261
|
-
|
|
262
|
-
#### options.toolbarConfig
|
|
263
|
-
|
|
264
|
-
| | 说明 | 默认值 |
|
|
265
|
-
| - | - | - |
|
|
266
|
-
| hide | 是否隐藏工具栏 | false |
|
|
267
|
-
| pin | 是否固定工具栏 | false |
|
|
268
|
-
|
|
269
|
-
#### options.counter
|
|
270
|
-
|
|
271
|
-
| | 说明 | 默认值 |
|
|
272
|
-
| - | - | - |
|
|
273
|
-
| enable | 是否启用计数器 | false |
|
|
274
|
-
| after(length: number, counter: options.counter): void | 字数统计回调 | - |
|
|
275
|
-
| max | 允许输入的最大值 | - |
|
|
276
|
-
| type | 统计类型:'markdown', 'text' | 'markdown' |
|
|
277
|
-
|
|
278
|
-
#### options.cache
|
|
279
|
-
|
|
280
|
-
| | 说明 | 默认值 |
|
|
281
|
-
| - | - | - |
|
|
282
|
-
| enable | 是否使用 localStorage 进行缓存 | true |
|
|
283
|
-
| id | 缓存 key,第一个参数为元素且启用缓存时**必填** | - |
|
|
284
|
-
| after(html: string): string | 缓存后的回调 | - |
|
|
285
|
-
|
|
286
|
-
#### options.comment
|
|
287
|
-
|
|
288
|
-
⚠️:仅支持 wysiwyg 模式
|
|
289
|
-
|
|
290
|
-
| | 说明 | 默认值 |
|
|
291
|
-
| - | - | - |
|
|
292
|
-
| enable | 是否启用评论模式 | false |
|
|
293
|
-
| add(id: string, text: string, commentsData: ICommentsData[]) | 添加评论回调 | - |
|
|
294
|
-
| remove(ids: string[]) | 删除评论回调 | - |
|
|
295
|
-
| scroll(top: number) | 滚动回调 | - |
|
|
296
|
-
| adjustTop(commentsData: ICommentsData[]) | 文档修改时,适配评论高度 | - |
|
|
297
|
-
|
|
298
|
-
#### options.preview
|
|
299
|
-
|
|
300
|
-
| | 说明 | 默认值 |
|
|
301
|
-
| - | - | - |
|
|
302
|
-
| delay | 预览 debounce 毫秒间隔 | 1000 |
|
|
303
|
-
| maxWidth | 预览区域最大宽度 | 800 |
|
|
304
|
-
| mode | 显示模式:both, editor | 'both' |
|
|
305
|
-
| url | md 解析请求 | - |
|
|
306
|
-
| parse(element: HTMLElement) | 预览回调 | - |
|
|
307
|
-
| transform(html: string): string | 渲染之前回调 | - |
|
|
308
|
-
|
|
309
|
-
#### options.preview.hljs
|
|
310
|
-
|
|
311
|
-
| | 说明 | 默认值 |
|
|
312
|
-
| - | - | - |
|
|
313
|
-
| defaultLang | 未指定语言时默认使用该语言 | '' |
|
|
314
|
-
| enable | 是否启用代码高亮 | true |
|
|
315
|
-
| style | 可选值参见[Chroma](https://xyproto.github.io/splash/docs/longer/all.html) | `github` |
|
|
316
|
-
| lineNumber | 是否启用行号 | false |
|
|
317
|
-
| langs | 自定义指定语言 | [CODE_LANGUAGES](https://github.com/Vanessa219/vditor/blob/53ca8f9a0e511b37b5dae7c6b15eb933e9e02ccd/src/ts/constants.ts#L20) |
|
|
318
|
-
| renderMenu(code: HTMLElement, copy: HTMLElement) | 渲染菜单按钮 | - |
|
|
319
|
-
|
|
320
|
-
#### options.preview.markdown
|
|
321
|
-
|
|
322
|
-
| | 说明 | 默认值 |
|
|
323
|
-
| - | - | - |
|
|
324
|
-
| autoSpace | 自动空格 | false |
|
|
325
|
-
| gfmAutoLink | 自动链接 | true |
|
|
326
|
-
| fixTermTypo | 自动矫正术语 | false |
|
|
327
|
-
| toc | 插入目录 | false |
|
|
328
|
-
| footnotes | 脚注 | true |
|
|
329
|
-
| codeBlockPreview | wysiwyg 和 ir 模式下是否对代码块进行渲染 | true |
|
|
330
|
-
| mathBlockPreview | wysiwyg 和 ir 模式下是否对数学公式进行渲染 | true |
|
|
331
|
-
| paragraphBeginningSpace | 段落开头空两个 | false |
|
|
332
|
-
| sanitize | 是否启用过滤 XSS | true |
|
|
333
|
-
| listStyle | 为列表添加 data-style 属性 | false |
|
|
334
|
-
| linkBase | 链接相对路径前缀 | '' |
|
|
335
|
-
| linkPrefix | 链接强制前缀 | '' |
|
|
336
|
-
| mark | 启用 mark 标记 | false |
|
|
337
|
-
| sup | 上标 | false |
|
|
338
|
-
| sub | 下标 | false |
|
|
339
|
-
|
|
340
|
-
#### options.preview.theme
|
|
341
|
-
|
|
342
|
-
| | 说明 | 默认值 |
|
|
343
|
-
| - | - | - |
|
|
344
|
-
| current | 当前主题 | "light" |
|
|
345
|
-
| list | 可选主题列表 | { "ant-design": "Ant Design", dark: "Dark", light: "Light", wechat: "WeChat" } |
|
|
346
|
-
| path | 主题样式地址 | `https://unpkg.com/vditor@${VDITOR_VERSION}/dist/css/content-theme` |
|
|
347
|
-
|
|
348
|
-
#### options.preview.math
|
|
349
|
-
|
|
350
|
-
| | 说明 | 默认值 |
|
|
351
|
-
| - | - | - |
|
|
352
|
-
| inlineDigit | 内联数学公式起始 $ 后是否允许数字 | false |
|
|
353
|
-
| macros | 使用 MathJax 渲染时传入的宏定义 | {} |
|
|
354
|
-
| engine | 数学公式渲染引擎:KaTeX, MathJax | 'KaTeX' |
|
|
355
|
-
| mathJaxOptions | 数学公式渲染引擎为 MathJax 时的参数 | - |
|
|
356
|
-
|
|
357
|
-
#### options.preview.actions?: Array<IPreviewAction | IPreviewActionCustom>
|
|
358
|
-
|
|
359
|
-
默认值为 ["desktop", "tablet", "mobile", "mp-wechat", "zhihu"]。
|
|
360
|
-
可从默认值中挑选进行配置,也可使用以下字段进行自定制开发。
|
|
361
|
-
|
|
362
|
-
| | 说明 | 默认值 |
|
|
363
|
-
| - | - | - |
|
|
364
|
-
| key | 按钮唯一标识,不能为空 | - |
|
|
365
|
-
| text | 按钮文字 | - |
|
|
366
|
-
| tooltip | 提示 | - |
|
|
367
|
-
| className | 按钮类名 | - |
|
|
368
|
-
| click(key: string) | 按钮点击回调事件 | - |
|
|
369
|
-
|
|
370
|
-
#### options.preview.render.media
|
|
371
|
-
|
|
372
|
-
| | 说明 | 默认值 |
|
|
373
|
-
|--------|-----------|------|
|
|
374
|
-
| enable | 是否启用多媒体渲染 | true |
|
|
375
|
-
|
|
376
|
-
#### options.image
|
|
377
|
-
|
|
378
|
-
| | 说明 | 默认值 |
|
|
379
|
-
| - | - | - |
|
|
380
|
-
| isPreview | 是否预览图片 | true |
|
|
381
|
-
| preview(bom: Element) => void | 图片预览处理 | - |
|
|
382
|
-
|
|
383
|
-
#### options.link
|
|
384
|
-
|
|
385
|
-
| | 说明 | 默认值 |
|
|
386
|
-
| - | - | - |
|
|
387
|
-
| isOpen | 是否打开链接地址 | true |
|
|
388
|
-
| click(bom: Element) => void | 点击链接事件 | - |
|
|
389
|
-
|
|
390
|
-
#### options.hint
|
|
391
|
-
|
|
392
|
-
| | 说明 | 默认值 |
|
|
393
|
-
| - | - | - |
|
|
394
|
-
| parse | 是否进行 md 解析 | true |
|
|
395
|
-
| delay | 提示 debounce 毫秒间隔 | 200 |
|
|
396
|
-
| emoji | 默认表情,可从[lute/emoji_map](https://github.com/88250/lute/blob/master/parse/emoji_map.go) 中选取,也可自定义 | { '+1': '👍', '-1': '👎', 'heart': '❤️', 'cold_sweat': '😰' } |
|
|
397
|
-
| emojiTail | 常用表情提示 | - |
|
|
398
|
-
| emojiPath | 表情图片地址 | `https://unpkg.com/vditor@${VDITOR_VERSION}/dist/images/emoji` |
|
|
399
|
-
| extend: IHintExtend[] | 对 @/话题等关键字自动补全的扩展 | [] |
|
|
400
|
-
|
|
401
|
-
```ts
|
|
402
|
-
interface IHintData {
|
|
403
|
-
html: string;
|
|
404
|
-
value: string;
|
|
405
|
-
}
|
|
165
|
+
基于 Lute 引擎,支持:
|
|
166
|
+
- CommonMark 规范
|
|
167
|
+
- GFM 规范
|
|
168
|
+
- 数学公式
|
|
169
|
+
- 图表
|
|
170
|
+
- 脑图
|
|
171
|
+
- 等等...
|
|
406
172
|
|
|
407
|
-
|
|
408
|
-
key: string;
|
|
173
|
+
### 6. 工具函数模块 (`src/ts/util/`)
|
|
409
174
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
175
|
+
| 文件 | 功能 |
|
|
176
|
+
|------|------|
|
|
177
|
+
| `Options.ts` | 配置选项合并与默认值 |
|
|
178
|
+
| `selection.ts` | 光标/选区操作 |
|
|
179
|
+
| `hasClosest.ts` | DOM 节点查找 |
|
|
180
|
+
| `imageResize.ts` | 图片拖拽调整尺寸 |
|
|
181
|
+
| `editorCommonEvent.ts` | 编辑器通用事件(复制/剪切/粘贴/拖拽等) |
|
|
182
|
+
| `fixBrowserBehavior.ts` | 浏览器行为修复 |
|
|
183
|
+
| `processCode.ts` | 代码块渲染处理 |
|
|
413
184
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
* 文件上传的数据结构如下。后端返回的数据结构不一致时,可使用 `format` 进行转换。
|
|
417
|
-
|
|
418
|
-
```js
|
|
419
|
-
// POST data
|
|
420
|
-
xhr.send(formData); // formData = FormData.append("file[]", File)
|
|
421
|
-
// return data
|
|
422
|
-
{
|
|
423
|
-
"msg": "",
|
|
424
|
-
"code": 0,
|
|
425
|
-
"data": {
|
|
426
|
-
"errFiles": ['filename', 'filename2'],
|
|
427
|
-
"succMap": {
|
|
428
|
-
"filename3": "filepath3",
|
|
429
|
-
"filename3": "filepath3"
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
```
|
|
185
|
+
---
|
|
434
186
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
```js
|
|
438
|
-
// POST data
|
|
439
|
-
xhr.send(JSON.stringify({url: src})); // src 为站外图片地址
|
|
440
|
-
// return data
|
|
441
|
-
{
|
|
442
|
-
msg: '',
|
|
443
|
-
code: 0,
|
|
444
|
-
data : {
|
|
445
|
-
originalURL: '',
|
|
446
|
-
url: ''
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
```
|
|
187
|
+
## 渲染流程
|
|
450
188
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
```js
|
|
454
|
-
if (xhr.status === 200) {
|
|
455
|
-
if (vditor.options.upload.success) {
|
|
456
|
-
vditor.options.upload.success(editorElement, xhr.responseText);
|
|
457
|
-
} else {
|
|
458
|
-
let responseText = xhr.responseText;
|
|
459
|
-
if (vditor.options.upload.format) {
|
|
460
|
-
responseText = vditor.options.upload.format(files as File [], xhr.responseText);
|
|
461
|
-
}
|
|
462
|
-
genUploadedLabel(responseText, vditor);
|
|
463
|
-
}
|
|
464
|
-
} else {
|
|
465
|
-
if (vditor.options.upload.error) {
|
|
466
|
-
vditor.options.upload.error(xhr.responseText);
|
|
467
|
-
} else {
|
|
468
|
-
vditor.tip.show(xhr.responseText);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
```
|
|
189
|
+
### WYSIWYG 模式渲染流程
|
|
472
190
|
|
|
473
|
-
| | 说明 | 默认值 |
|
|
474
|
-
| - | - | - |
|
|
475
|
-
| xhr | 上传时使用的 XMLHttpRequest | - |
|
|
476
|
-
| url | 上传 url,为空则不会触发上传相关事件 | '' |
|
|
477
|
-
| max | 上传文件最大 Byte | 10 * 1024 * 1024 |
|
|
478
|
-
| linkToImgUrl | 剪切板中包含图片地址时,使用此 url 重新上传 | '' |
|
|
479
|
-
| linkToImgCallback(responseText: string) | 图片地址上传回调 | - |
|
|
480
|
-
| linkToImgFormat(responseText: string): string | 对图片地址上传的返回值进行格式化 | - |
|
|
481
|
-
| success(editor: HTMLPreElement, msg: string) | 上传成功回调 | - |
|
|
482
|
-
| error(msg: string) | 上传失败回调 | - |
|
|
483
|
-
| token | CORS 上传验证,头为 X-Upload-Token | - |
|
|
484
|
-
| withCredentials | 跨站点访问控制 | false |
|
|
485
|
-
| headers | 请求头设置 | - |
|
|
486
|
-
| filename(name: string): string | 文件名安全处理 | name => name.replace(/\W/g, '') |
|
|
487
|
-
| accept | 文件上传类型,同[input accept](https://www.w3schools.com/tags/att_input_accept.asp) | - |
|
|
488
|
-
| validate(files: File[]) => string \| boolean | 校验,成功时返回 true 否则返回错误信息 | - |
|
|
489
|
-
| handler(files: File[]) => string \| null \| Promise<string> \| Promise<null> | 自定义上传,当发生错误时返回错误信息 | - |
|
|
490
|
-
| format(files: File[], responseText: string): string | 对服务端返回的数据进行转换,以满足内置的数据结构 | - |
|
|
491
|
-
| file(files: File[]): File[] \| Promise<File[]> | 将上传的文件处理后再返回 | - |
|
|
492
|
-
| cancel(files: File[]): void | 取消正在上传的文件 | - |
|
|
493
|
-
| setHeaders(): { [key: string]: string } | 上传前使用返回值设置头 | - |
|
|
494
|
-
| extraData: { [key: string]: string \| Blob } | 为 FormData 添加额外的参数 | - |
|
|
495
|
-
| multiple | 上传文件是否为多个 | true |
|
|
496
|
-
| fieldName | 上传字段名称 | 'file[]' |
|
|
497
|
-
| renderLinkDest?(vditor: IVditor, node: ILuteNode, entering: boolean): [string, number] | 处理剪贴板中的图片地址 | '' |
|
|
498
|
-
|
|
499
|
-
#### options.resize
|
|
500
|
-
|
|
501
|
-
| | 说明 | 默认值 |
|
|
502
|
-
| - | - | - |
|
|
503
|
-
| enable | 是否支持大小拖拽 | false |
|
|
504
|
-
| position | 拖拽栏位置:'top', 'bottom' | 'bottom' |
|
|
505
|
-
| after(height: number) | 拖拽结束的回调 | - |
|
|
506
|
-
|
|
507
|
-
#### options.classes
|
|
508
|
-
|
|
509
|
-
| | 说明 | 默认值 |
|
|
510
|
-
| - | - | - |
|
|
511
|
-
| preview | 预览元素上的 className | '' |
|
|
512
|
-
|
|
513
|
-
#### options.fullscreen
|
|
514
|
-
|
|
515
|
-
| | 说明 | 默认值 |
|
|
516
|
-
| - | - | - |
|
|
517
|
-
| index | 全屏层级 | 90 |
|
|
518
|
-
|
|
519
|
-
#### options.outline
|
|
520
|
-
|
|
521
|
-
| | 说明 | 默认值 |
|
|
522
|
-
| - | - | - |
|
|
523
|
-
| enable | 初始化是否展现大纲 | false |
|
|
524
|
-
| position | 大纲位置:'left', 'right' | 'left' |
|
|
525
|
-
|
|
526
|
-
#### methods
|
|
527
|
-
|
|
528
|
-
| | 说明 |
|
|
529
|
-
| - | - |
|
|
530
|
-
| exportJSON(markdown: string) | 根据 Markdown 获取对应 JSON |
|
|
531
|
-
| getValue() | 获取 Markdown 内容 |
|
|
532
|
-
| getHTML() | 获取 HTML 内容 |
|
|
533
|
-
| insertValue(value: string, render = true) | 在焦点处插入内容,并默认进行 Markdown 渲染 |
|
|
534
|
-
| focus() | 聚焦到编辑器 |
|
|
535
|
-
| blur() | 让编辑器失焦 |
|
|
536
|
-
| disabled() | 禁用编辑器 |
|
|
537
|
-
| enable() | 解除编辑器禁用 |
|
|
538
|
-
| getSelection(): string | 返回选中的字符串 |
|
|
539
|
-
| setValue(markdown: string, clearStack = false) | 设置编辑器内容且选中清空历史栈 |
|
|
540
|
-
| clearStack() | 清空撤销和重做记录栈|
|
|
541
|
-
| renderPreview(value?: string) | 设置预览区域内容 |
|
|
542
|
-
| getCursorPosition():{top: number, left: number} | 获取焦点位置 |
|
|
543
|
-
| deleteValue() | 删除选中内容 |
|
|
544
|
-
| updateValue(value: string) | 更新选中内容 |
|
|
545
|
-
| isUploading() | 上传是否还在进行中 |
|
|
546
|
-
| clearCache() | 清除缓存 |
|
|
547
|
-
| disabledCache() | 禁用缓存 |
|
|
548
|
-
| enableCache() | 启用缓存 |
|
|
549
|
-
| html2md(value: string) | HTML 转 md |
|
|
550
|
-
| tip(text: string, time: number) | 消息提示。time 为 0 将一直显示 |
|
|
551
|
-
| setPreviewMode(mode: "both" \| "editor") | 设置预览模式 |
|
|
552
|
-
| setTheme(theme: "dark" \| "classic", contentTheme?: string, codeTheme?: string, contentThemePath?: string) | 设置主题、内容主题及代码块风格 |
|
|
553
|
-
| getCurrentMode(): string | 获取编辑器当前编辑模式 |
|
|
554
|
-
| destroy() | 销毁编辑器 |
|
|
555
|
-
| getCommentIds(): {id: string, top: number}[] | 获取所有评论 |
|
|
556
|
-
| hlCommentIds(ids: string[]) | 高亮评论 |
|
|
557
|
-
| unHlCommentIds(ids: string[]) | 取消评论高亮 |
|
|
558
|
-
| removeCommentIds(removeIds: string[]) | 删除评论 |
|
|
559
|
-
| updateToolbarConfig(config: {hide?: boolean, pin?: boolean}) | 更新工具栏配置 |
|
|
560
|
-
| insertEmptyBlock(position: InsertPosition) | 插入空快 |
|
|
561
|
-
|
|
562
|
-
#### static methods
|
|
563
|
-
|
|
564
|
-
* 不需要进行编辑操作时,仅需引入 [`method.min.js`](https://unpkg.com/vditor/dist/) 后如下直接调用
|
|
565
|
-
|
|
566
|
-
```js
|
|
567
|
-
Vditor.mermaidRender(document)
|
|
568
191
|
```
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
192
|
+
用户输入
|
|
193
|
+
↓
|
|
194
|
+
input.ts (keydown/paste/cut/drop)
|
|
195
|
+
↓
|
|
196
|
+
getMarkdown.ts (获取当前 Markdown)
|
|
197
|
+
↓
|
|
198
|
+
Lute 引擎 (Markdown → HTML)
|
|
199
|
+
↓
|
|
200
|
+
renderDomByMd.ts (SpinVditorDOM)
|
|
201
|
+
├─ preprocessImageSize() (图片尺寸预处理)
|
|
202
|
+
├─ processImageSizeInDOM() (图片尺寸后处理)
|
|
203
|
+
└─ processDocLinkInWYSIWYG() (文档链接处理)
|
|
204
|
+
↓
|
|
205
|
+
afterRenderEvent.ts (渲染后事件)
|
|
206
|
+
↓
|
|
207
|
+
undo.ts (保存撤销栈)
|
|
208
|
+
↓
|
|
209
|
+
cache.ts (本地缓存)
|
|
573
210
|
```
|
|
574
211
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
```ts
|
|
578
|
-
previewElement: HTMLDivElement, // 使用该元素进行渲染
|
|
579
|
-
markdown: string, // 需要渲染的 markdown 原文
|
|
580
|
-
options?: IPreviewOptions {
|
|
581
|
-
mode: "dark" | "light";
|
|
582
|
-
anchor?: number; // 为标题添加锚点 0:不渲染;1:渲染于标题前;2:渲染于标题后,默认 0
|
|
583
|
-
customEmoji?: { [key: string]: string }; // 自定义 emoji,默认为 {}
|
|
584
|
-
lang?: (keyof II18nLang); // 语言,默认为 'zh_CN'
|
|
585
|
-
emojiPath?: string; // 表情图片路径
|
|
586
|
-
hljs?: IHljs; // 参见 options.preview.hljs
|
|
587
|
-
speech?: { // 对选中后的内容进行阅读
|
|
588
|
-
enable?: boolean,
|
|
589
|
-
};
|
|
590
|
-
math?: IMath; // 数学公式渲染配置
|
|
591
|
-
cdn?: string; // 自建 CDN 地址
|
|
592
|
-
transform?(html: string): string; // 在渲染前进行的回调方法
|
|
593
|
-
after?(); // 渲染完成后的回调
|
|
594
|
-
lazyLoadImage?: string; // 设置为 Loading 图片地址后将启用图片的懒加载
|
|
595
|
-
markdown?: options.preview.markdown;
|
|
596
|
-
theme?: options.preview.theme;
|
|
597
|
-
render?: options.preview.render;
|
|
598
|
-
renderers?: ILuteRender; // 自定义渲染 https://ld246.com/article/1588412297062
|
|
599
|
-
}
|
|
600
|
-
```
|
|
212
|
+
### 图片尺寸语法(自定义扩展)
|
|
601
213
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
| | 说明 |
|
|
605
|
-
| - | - |
|
|
606
|
-
| previewImage(oldImgElement: HTMLImageElement, lang: keyof II18n = "zh_CN", theme = "classic") | 点击图片预览 |
|
|
607
|
-
| mermaidRender(element: HTMLElement, cdn = options.cdn, theme = options.theme) | 流程图/时序图/甘特图 |
|
|
608
|
-
| SMILESRender(element: HTMLElement, cdn = options.cdn, theme = options.theme) | 化学物质结构 |
|
|
609
|
-
| markmapRender(element: HTMLElement, cdn = options.cdn) | markdown 思维导图 |
|
|
610
|
-
| flowchartRender(element: HTMLElement, cdn = options.cdn) | flowchart 渲染 |
|
|
611
|
-
| codeRender(element: HTMLElement, option?: IHljs) | 为 element 中的代码块添加复制按钮 |
|
|
612
|
-
| chartRender(element: (HTMLElement \| Document) = document, cdn = options.cdn, theme = options.theme) | 图表渲染 |
|
|
613
|
-
| mindmapRender(element: (HTMLElement \| Document) = document, cdn = options.cdn, theme = options.theme) | 脑图渲染 |
|
|
614
|
-
| plantumlRender(element: (HTMLElement \| Document) = document, cdn = options.cdn) | plantuml 渲染 |
|
|
615
|
-
| abcRender(element: (HTMLElement \| Document) = document, cdn = options.cdn) | 五线谱渲染 |
|
|
616
|
-
| md2html(mdText: string, options?: IPreviewOptions): Promise\<string> | Markdown 文本转换为 HTML,该方法需使用[异步编程](https://ld246.com/article/1546828434083?r=Vanessa#toc_h3_1) |
|
|
617
|
-
| preview(previewElement: HTMLDivElement, markdown: string, options?: IPreviewOptions) | 页面 Markdown 文章渲染 |
|
|
618
|
-
| highlightRender(hljsOption?: IHljs, element?: HTMLElement \| Document, cdn = options.cdn) | 为 element 中的代码块进行高亮渲染 |
|
|
619
|
-
| mediaRender(element: HTMLElement) | 为[特定链接](https://ld246.com/article/1589813914768)分别渲染为视频、音频、嵌入的 iframe |
|
|
620
|
-
| mathRender(element: HTMLElement, options?: {cdn?: string, math?: IMath}) | 对数学公式进行渲染 |
|
|
621
|
-
| speechRender(element: HTMLElement, lang?: (keyof II18nLang)) | 对选中的文字进行阅读 |
|
|
622
|
-
| graphvizRender(element: HTMLElement, cdn?: string) | 对 graphviz 进行渲染 |
|
|
623
|
-
| outlineRender(contentElement: HTMLElement, targetElement: Element) | 对大纲进行渲染 |
|
|
624
|
-
| lazyLoadImageRender(element: (HTMLElement \| Document) = document) | 对启用懒加载的图片进行渲染 |
|
|
625
|
-
| setCodeTheme(codeTheme: string, cdn = options.cdn) | 设置代码主题,codeTheme 参见 options.preview.hljs.style |
|
|
626
|
-
| setContentTheme(contentTheme: string, path: string) | 设置内容主题,contentTheme 参见 options.preview.theme.list |
|
|
627
|
-
|
|
628
|
-
## 🏛️ 项目架构
|
|
629
|
-
|
|
630
|
-
### 一、架构概述
|
|
631
|
-
|
|
632
|
-
Vditor 采用模块化架构,支持三种编辑模式:
|
|
633
|
-
|
|
634
|
-
| 模式 | 说明 | 目录 |
|
|
635
|
-
|------|------|------|
|
|
636
|
-
| WYSIWYG | 所见即所得模式 | [src/ts/wysiwyg/](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/wysiwyg/) |
|
|
637
|
-
| IR | 即时渲染模式 | [src/ts/ir/](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/ir/) |
|
|
638
|
-
| SV | 分屏预览模式 | [src/ts/sv/](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/sv/) |
|
|
639
|
-
|
|
640
|
-
### 二、核心目录结构
|
|
214
|
+
- 普通语法:`` → 自动添加默认尺寸 300x200
|
|
215
|
+
- 带尺寸语法:`` → 使用指定尺寸
|
|
641
216
|
|
|
642
|
-
|
|
643
|
-
src/
|
|
644
|
-
├── index.ts # 主入口,Vditor 类
|
|
645
|
-
├── method.ts # 静态工具方法
|
|
646
|
-
├── assets/ # 静态资源
|
|
647
|
-
│ ├── less/ # 样式文件
|
|
648
|
-
│ ├── images/ # 图片资源
|
|
649
|
-
│ └── js/ # 第三方库 (highlight, katex, mermaid, lute 等)
|
|
650
|
-
└── ts/ # TypeScript 源码
|
|
651
|
-
├── constants.ts # 常量定义
|
|
652
|
-
├── ir/ # IR 模式 (即时渲染模式)
|
|
653
|
-
├── sv/ # SV 模式 (分屏预览模式)
|
|
654
|
-
├── wysiwyg/ # WYSIWYG 模式 (所见即所得)
|
|
655
|
-
├── toolbar/ # 工具栏
|
|
656
|
-
├── markdown/ # Markdown 渲染相关
|
|
657
|
-
├── preview/ # 预览相关
|
|
658
|
-
├── hint/ # 提示补全
|
|
659
|
-
├── upload/ # 文件上传
|
|
660
|
-
├── undo/ # 撤销重做
|
|
661
|
-
├── util/ # 工具函数
|
|
662
|
-
└── ui/ # UI 相关
|
|
663
|
-
```
|
|
217
|
+
### 文档链接语法(自定义扩展)
|
|
664
218
|
|
|
665
|
-
|
|
219
|
+
- 语法:`((1225096851397541888 "测试"))` → 渲染为带 id 的链接
|
|
666
220
|
|
|
667
|
-
|
|
668
|
-
|------|------|
|
|
669
|
-
| [index.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/wysiwyg/index.ts) | 主类,绑定事件(复制/剪切/粘贴/拖拽等) |
|
|
670
|
-
| [input.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/wysiwyg/input.ts) | 输入处理,调用 SpinVditorDOM 渲染 |
|
|
671
|
-
| [renderDomByMd.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/wysiwyg/renderDomByMd.ts) | Markdown 渲染 + **图片尺寸处理** |
|
|
672
|
-
| [afterRenderEvent.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/wysiwyg/afterRenderEvent.ts) | 渲染后事件处理 |
|
|
221
|
+
---
|
|
673
222
|
|
|
674
|
-
|
|
223
|
+
## 扩展功能模块
|
|
675
224
|
|
|
676
|
-
|
|
677
|
-
- 普通语法:`` → 自动添加默认尺寸 300x200
|
|
678
|
-
- 带尺寸语法:`` → 使用指定尺寸
|
|
225
|
+
### 1. 预览模块 (`src/ts/preview/`)
|
|
679
226
|
|
|
680
|
-
|
|
227
|
+
- `Preview.ts`: 预览类
|
|
228
|
+
- `render.ts`: 渲染预览内容
|
|
229
|
+
- `theme.ts`: 预览主题切换
|
|
230
|
+
- 支持内容主题:ant-design, light, dark, wechat
|
|
681
231
|
|
|
682
|
-
|
|
683
|
-
|------|------|
|
|
684
|
-
| [renderDomByMd.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/wysiwyg/renderDomByMd.ts) | **预处理**:`preprocessImageSize()` 在 Markdown 层面添加默认尺寸<br>**后处理**:`processImageSizeInDOM()` 转换文本为 `<img>` 标签 |
|
|
685
|
-
| [imageResize.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/imageResize.ts) | **拖拽resize**:四角检测 (nw/ne/sw/se),无蓝色手柄,鼠标悬停变色 |
|
|
686
|
-
| [getMarkdown.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/markdown/getMarkdown.ts) | **导出Markdown**:`processImageSizeInHTML()` 将 `<img>` 转回 `` 语法 |
|
|
232
|
+
### 2. 提示补全模块 (`src/ts/hint/`)
|
|
687
233
|
|
|
688
|
-
|
|
234
|
+
- 表情自动补全
|
|
235
|
+
- @用户自动补全
|
|
236
|
+
- #话题自动补全
|
|
237
|
+
- 支持自定义扩展
|
|
689
238
|
|
|
690
|
-
|
|
691
|
-
|------|------|
|
|
692
|
-
| [Options.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/Options.ts) | 配置选项合并 |
|
|
693
|
-
| [selection.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/selection.ts) | 光标/选区操作 |
|
|
694
|
-
| [fixBrowserBehavior.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/fixBrowserBehavior.ts) | 浏览器行为修复 |
|
|
695
|
-
| [editorCommonEvent.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/editorCommonEvent.ts) | 编辑器通用事件 (复制/剪切/粘贴/拖拽等) |
|
|
696
|
-
| [imageResize.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/imageResize.ts) | 图片拖拽调整尺寸 |
|
|
697
|
-
| [processCode.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/processCode.ts) | 代码块渲染处理 |
|
|
698
|
-
| [hasClosest.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/hasClosest.ts) | DOM 节点查找 |
|
|
239
|
+
### 3. 文件上传模块 (`src/ts/upload/`)
|
|
699
240
|
|
|
700
|
-
|
|
241
|
+
- 拖拽上传
|
|
242
|
+
- 粘贴上传
|
|
243
|
+
- 实时进度
|
|
244
|
+
- CORS 跨域
|
|
245
|
+
- 支持自定义上传处理
|
|
701
246
|
|
|
702
|
-
|
|
703
|
-
用户输入 → input.ts → SpinVditorDOM(html) → processImageSizeInDOM() → afterRenderEvent()
|
|
704
|
-
↑
|
|
705
|
-
preprocessImageSize() 在 Markdown 层面添加默认尺寸(初始化时)
|
|
706
|
-
```
|
|
247
|
+
### 4. 撤销重做模块 (`src/ts/undo/`)
|
|
707
248
|
|
|
708
|
-
|
|
249
|
+
- 实时保存历史栈
|
|
250
|
+
- 支持撤销
|
|
251
|
+
- 支持重做
|
|
709
252
|
|
|
710
|
-
###
|
|
253
|
+
### 5. 大纲模块 (`src/ts/outline/`)
|
|
711
254
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
* [Lute 一款对中文语境优化的 Markdown 引擎,支持 Go 和 JavaScript](https://ld246.com/article/1567047822949)
|
|
255
|
+
- 目录生成
|
|
256
|
+
- 跳转导航
|
|
715
257
|
|
|
716
|
-
###
|
|
258
|
+
### 6. 评论模块 (`src/ts/comment/`)
|
|
717
259
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
5. 修改代码
|
|
723
|
-
6. `npm run build` 打包代码到 dist 目录
|
|
260
|
+
- 仅 WYSIWYG 模式支持
|
|
261
|
+
- 高亮评论
|
|
262
|
+
- 删除评论
|
|
263
|
+
- 滚动定位
|
|
724
264
|
|
|
725
|
-
###
|
|
265
|
+
### 7. 调整大小模块 (`src/ts/resize/`)
|
|
726
266
|
|
|
727
|
-
|
|
267
|
+
- 编辑器高度拖拽调整
|
|
728
268
|
|
|
729
|
-
|
|
269
|
+
---
|
|
730
270
|
|
|
731
|
-
|
|
732
|
-
* `highlightRender`,`mathRender`,`abcRender`,`chartRender`,`mermaidRender`,`SMILESRender`,`markmapRender`,`flowchartRender`,`mindmapRender`,`plantumlRender`,`graphvizRender`,`setCodeTheme`,`setContentTheme` 方法中需添加 cdn 参数
|
|
733
|
-
* 将 build 成功的 dist 目录或 [jsDelivr](https://www.jsdelivr.com/package/npm/vditor?path=dist) 中的 dist 目录拷贝至正确的位置
|
|
271
|
+
## 开发环境
|
|
734
272
|
|
|
735
|
-
###
|
|
273
|
+
### 安装依赖
|
|
736
274
|
|
|
737
|
-
|
|
275
|
+
```bash
|
|
276
|
+
npm install
|
|
277
|
+
```
|
|
738
278
|
|
|
739
|
-
|
|
279
|
+
### 启动开发服务器
|
|
740
280
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
281
|
+
```bash
|
|
282
|
+
npm run start
|
|
283
|
+
```
|
|
744
284
|
|
|
745
|
-
|
|
285
|
+
访问 http://localhost:9000
|
|
746
286
|
|
|
747
|
-
|
|
748
|
-
* [讨论区](https://ld246.com/tag/vditor)
|
|
749
|
-
* [报告问题](https://github.com/Vanessa219/vditor/issues/new)
|
|
287
|
+
### 打包构建
|
|
750
288
|
|
|
751
|
-
|
|
289
|
+
```bash
|
|
290
|
+
npm run build
|
|
291
|
+
```
|
|
752
292
|
|
|
753
|
-
|
|
293
|
+
输出到 `dist/` 目录
|
|
754
294
|
|
|
755
|
-
|
|
295
|
+
### 常用命令
|
|
756
296
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
* [incubator-echarts](https://github.com/apache/incubator-echarts):A powerful, interactive charting and visualization library for browser
|
|
761
|
-
* [abcjs](https://github.com/paulrosen/abcjs):JavaScript library for rendering standard music notation in a browser
|
|
297
|
+
- `npm run build`: 生产构建
|
|
298
|
+
- `npm run start`: 启动开发服务器
|
|
299
|
+
- `npm run test`: 运行测试
|
|
762
300
|
|
|
763
|
-
|
|
301
|
+
---
|
|
764
302
|
|
|
765
|
-
|
|
303
|
+
## 核心技术栈
|
|
766
304
|
|
|
767
|
-
|
|
305
|
+
- TypeScript
|
|
306
|
+
- Lute (Markdown 解析引擎)
|
|
307
|
+
- highlight.js (代码高亮)
|
|
308
|
+
- KaTeX/MathJax (数学公式)
|
|
309
|
+
- Mermaid (流程图)
|
|
310
|
+
- ECharts (图表)
|
|
311
|
+
- abcjs (五线谱)
|
|
768
312
|
|
|
769
|
-
|
|
313
|
+
---
|
|
770
314
|
|
|
771
|
-
|
|
315
|
+
## 授权
|
|
772
316
|
|
|
773
|
-
|
|
317
|
+
MIT
|